﻿using Newtonsoft.Json;

using NPOI.XSSF.Streaming.Values;

using PLCS.Domain.Shared.Stations;
using PLCS.Domain.Trays;

namespace PLCS.Domain.Stations;

public class Station : BaseEntity
{
    /// <summary>
    /// 工厂编码
    /// </summary>
    public string? SiteNo { get; set; }

    /// <summary>
    /// 车间编码
    /// </summary>
    public string? AreaNo { get; set; }

    /// <summary>
    /// 产线编码
    /// </summary>
    public string? PdLineNo { get; set; }

    /// <summary>
    /// 工位名称
    /// </summary>
    public string StaName { get; set; }

    /// <summary>
    /// 工位名称MES
    /// </summary>
    public string StaName_Higher { get; set; }

    /// <summary>
    /// 工位名称PLC
    /// </summary>

    public string StaName_Lower { get; set; }

    /// <summary>
    /// 工位编号
    /// </summary>
    public string StaNum { get; init; }

    /// <summary>
    /// 工位类型
    /// </summary>
    public StationType StationType { get; set; }

    /// <summary>
    ///  最高容量
    /// </summary>
    public int Capacity { get; set; }

    /// <summary>
    /// 兼容托盘类型
    /// </summary>
    public string MultipleTrayType { get; set; }

    /// <summary>
    /// 兼容物料高度
    /// </summary>
    public int MultipleMaterialSize { get; set; }

    /// <summary>
    /// 当前托盘类型
    /// </summary>
    public TrayType CurrentTrayType { get; set; }

    /// <summary>
    /// 当前物料尺寸
    /// </summary>
    public int CurrentMaterialSize { get; set; }

    /// <summary>
    /// 当前个数
    /// </summary>
    public int TrayCount
    {
        get
        {
            if (StationType != StationType.栈工位 && StationType != StationType.队列工位)
            {
                return (int)HaveStatus;
            }
            else
            {
                return TrayCount;
            }
        }
        set { }
    }

    /// <summary>
    /// 对应每个设备的能否出件状态的json格式
    /// </summary>
    public string? CanOutStatusJson { get; set; }

    [NotMapped]
    public Dictionary<string, YesNo> CanOutStatus
    {
        get
        {
            if (!string.IsNullOrEmpty(CanOutStatusJson))
            {
                return JsonConvert.DeserializeObject<Dictionary<string, YesNo>>(CanOutStatusJson);
            }
            else
            {
                return new Dictionary<string, YesNo>();
            }
        }
    }

    /// <summary>
    /// 对应每个设备的能否进件状态的json格式
    /// </summary>
    public string? CanInSideStatusJson { get; set; }

    [NotMapped]
    public Dictionary<string, YesNo> CanInSideStatus
    {
        get
        {
            if (!string.IsNullOrEmpty(CanInSideStatusJson))
            {
                return JsonConvert.DeserializeObject<Dictionary<string, YesNo>>(CanInSideStatusJson);
            }
            else
            {
                return new Dictionary<string, YesNo>();
            }
        }
    }
    /// <summary>
    /// 可取
    /// </summary>
    public bool CanSend { set; get; }=false;
    /// <summary>
    /// 可送
    /// </summary>
    public bool CanGet { set; get; } =false;
    /// <summary>
    /// 空满位状态
    /// </summary>
    public YesNo HaveStatus { get;  set; } = YesNo.否;

    /// <summary>
    /// 分类（工位的功能，比如多个工位同属于低压缓存）
    /// </summary>
    public string Kind { get; set; }

    /// <summary>
    /// 优先级（在同一个分类下，会考虑优先级）
    /// </summary>
    public int Level { get; set; }

    /// <summary>
    /// 最近一次进工位时间
    /// </summary>
    public DateTime? LastEnterDate { get; set; }

    /// <summary>
    /// 完工信号
    /// </summary>
    public YesNo Completion_Signal { get; set; }

    /// <summary>
    /// 缓存工位
    /// </summary>
    public string? CacheStation { get; set; }

    /// <summary>
    /// 当前重量
    /// </summary>
    public int Weight { get; set; }

    /// <summary>
    /// 故障代码
    /// </summary>
    public int ErrCode { get; set; }

    /// <summary>
    /// 坐标位置
    /// </summary>
    public int Position { get; set; }

    /// <summary>
    /// 工位锁定状态
    /// </summary>
    public YesNo IsLocked { get; set; }

    /// <summary>
    /// 可取设备
    /// </summary>
    public string? CanTake_EquNum { get; set; }

    /// <summary>
    /// 可送设备
    /// </summary>
    public string? CanSend_EquNum { get; set; }

    /// <summary>
    /// 是否使用
    /// </summary>
    public YesNo IsUse { get; set; } = YesNo.是;
    /// <summary>
    /// 是否被使用
    /// </summary>
    public bool IsBeUsed { get; set; }= false;
    /// <summary>
    /// 满位状态变化触发事件
    /// </summary>
    public string? FullChangedMethod { get; set; }

    /// <summary>
    /// 满位状态变化参数
    /// </summary>
    public string? FullChangedParam { get; set; }

    /// <summary>
    /// 变空位变化触发方案
    /// </summary>
    public string? EmptyChangedMethod { get; set; }

    /// <summary>
    /// 变空位变化触发参数
    /// </summary>
    public string? EmptyChangedParam { get; set; }

    /// <summary>
    /// 当前托盘
    /// </summary>
    public ICollection<Tray>? Trays { get; set; }

    [NotMapped]
    public Stack<Tray>? StackTrays { get; set; }

    [NotMapped]
    public Queue<Tray>? QueueTrays { get; set; }

    private Station()
    {
    }

    public Station(
        string staName,
        string staName_Higher,
        string staName_Lower,
        string staNum,
        StationType staType,
        string multipleTrayType,
        string kind,
        int level,
        string? cacheStation = null,
        string? canTake_EquNum = null,
        string? canSend_EquNum = null,
        YesNo isUse = default,
        string? fullChangedMethod = null,
        string? emptyChangedMethod = null,
        string? siteNo = null,
        string? areaNo = null,
        string? pdLineNo = null)
    {
        StaName = staName;
        StaName_Higher = staName_Higher;
        StaName_Lower = staName_Lower;
        StaNum = staNum;
        StationType = staType;
        Kind = kind;
        Level = level;
        MultipleTrayType = multipleTrayType;
        CacheStation = cacheStation;
        IsUse = isUse;
        FullChangedMethod = fullChangedMethod;
        EmptyChangedMethod = emptyChangedMethod;
        SiteNo = siteNo;
        AreaNo = areaNo;
        PdLineNo = pdLineNo;
        CanTake_EquNum = canTake_EquNum;
        CanSend_EquNum = canSend_EquNum;
        InitalCanOutAndInStatus();
    }

    public void InitalCanOutAndInStatus()
    {
        if (!string.IsNullOrEmpty(CanTake_EquNum))
        {
            var canOutStatus = new Dictionary<string, YesNo>();
            foreach (var item in CanTake_EquNum.Split(ConstantChar.SplitChar))
            {
                canOutStatus.Add(item, YesNo.是);
            }
            CanOutStatusJson = JsonConvert.SerializeObject(canOutStatus);
        }
        if (!string.IsNullOrEmpty(CanSend_EquNum))
        {
            var canInStatus = new Dictionary<string, YesNo>();
            foreach (var item in CanSend_EquNum.Split(ConstantChar.SplitChar))
            {
                canInStatus.Add(item, YesNo.是);
            }
            CanInSideStatusJson = JsonConvert.SerializeObject(canInStatus);
        }
    }

    public string UpdateCanOutStatus(string equipmentNo, YesNo status)
    {
        YesNo outStatus;
        var isExist = CanOutStatus.TryGetValue(equipmentNo, out outStatus);
        if (isExist)
        {
            CanOutStatus[equipmentNo] = status;
        }
        else
        {
            CanOutStatus.Add(equipmentNo, status);
        }
        return JsonConvert.SerializeObject(CanOutStatus);
    }

    public string UpdateCanInStatus(string equipmentNo, YesNo status)
    {
        YesNo outStatus;
        var isExist = CanOutStatus.TryGetValue(equipmentNo, out outStatus);
        if (isExist)
        {
            CanInSideStatus[equipmentNo] = status;
        }
        else
        {
            CanInSideStatus.Add(equipmentNo, status);
        }
        return JsonConvert.SerializeObject(CanInSideStatus);
    }
    /// <summary>
    /// 改变空满位置状态
    /// </summary>
    /// <param name="status"></param>
    /// <returns></returns>
    public Station ChangeHaveStatus(YesNo status)
    {
        HaveStatus = status;
        AddLocalEvent(
            new StationHaveStatusChangeEvent()
            {
                HaveStatus = status,
                StaNum = StaNum,
                EmptyChangedMethod = EmptyChangedMethod,
                EmptyChangedParam = EmptyChangedParam,
                FullChangedMethod = FullChangedMethod,
                FullChangedParam = FullChangedParam,
            }
            );
        return this;
    }

    public void AddTray(Tray tray)
    {
        //if (Capacity == TrayCount)
        //    throw new ArgumentException($"'{StaNum}'工位已满，请确认");
        Trays ??= new List<Tray>();
        tray.EnterTime = DateTime.Now;
        switch (StationType)
        {
            case StationType.栈工位:
                StackTrays ??= new Stack<Tray>();
                if (StackTrays.Count < Capacity)
                {
                    StackTrays.Push(tray);
                    Trays.Add(tray);
                    //TrayCount++;
                }
                break;

            case StationType.队列工位:
                QueueTrays ??= new Queue<Tray>();
                if (QueueTrays.Count < Capacity)
                {
                    QueueTrays.Enqueue(tray);
                    Trays.Add(tray);
                    //TrayCount++;
                }
                break;

            case StationType.普通工位 or StationType.无光电货位:

                Trays.Add(tray);
                //TrayCount++;
                break;
        }
    }

    public Tray RemoveTray()
    {
        Trays ??= new List<Tray>();
        //if (TrayCount == 0)
        //    return null;
        switch (StationType)
        {
            case StationType.栈工位:
                StackTrays ??= new Stack<Tray>();
                if (StackTrays.Count > 0)
                {
                    var res = StackTrays.Pop();
                    Trays.Remove(res);
                    res.EnterTime = null;
                    //TrayCount--;
                    return res;
                }
                else
                {
                    return null;
                }
            case StationType.队列工位:
                QueueTrays ??= new Queue<Tray>();
                if (QueueTrays.Count > 0)
                {
                    var res = QueueTrays.Dequeue();
                    Trays.Remove(res);
                    res.EnterTime = null;
                    //TrayCount--;
                    return res;
                }
                else
                {
                    return null;
                }
            case StationType.普通工位 or StationType.无光电货位:

                var tray = Trays.First();
                Trays.Remove(tray);
                tray.EnterTime = null;
                //TrayCount--;
                return tray;

            default:
                return null;
        }
    }

    public Tray GetTray()
    {
        Trays ??= new List<Tray>();
        switch (StationType)
        {
            case StationType.栈工位:
                StackTrays ??= new Stack<Tray>();
                if (StackTrays.Count > 0)
                {
                    return StackTrays.Peek();
                }
                else
                {
                    return null;
                }
            case StationType.队列工位:
                QueueTrays ??= new Queue<Tray>();
                if (QueueTrays.Count > 0)
                {
                    return QueueTrays.Peek();
                }
                else
                {
                    return null;
                }
            case StationType.普通工位 or StationType.无光电货位:

                if (Trays.Count > 0)
                    return Trays.First();
                else
                    return null;

            default:
                return null;
        }
    }
}